package com.dongxing.concyrrency.chapter10;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

/**
 * @author XavierDong
 **/
public class BooleanLock implements Lock {

    /**
     * The initValue is true indicated the lock have be get.
     * The initValue is false indicated the lock is free(other Thread can get this.).
     */
    private Boolean initValue = Boolean.FALSE;

    private final Collection<Thread> blockedThreadCollections = new ArrayList<>();

    private Thread currentThread;

    @Override
    public synchronized void lock() throws InterruptedException {
        // 代表当前锁被某个线程持有，其他线程都处于等待接待
        while (Boolean.TRUE.equals(this.initValue)) {
            blockedThreadCollections.add(Thread.currentThread());
            this.wait();
        }
        // 代表没人持有锁了，当前线程持有了锁，在等待中的列表可以移除
        blockedThreadCollections.remove(Thread.currentThread());
        this.currentThread = Thread.currentThread();
        this.initValue = Boolean.TRUE;
    }

    @Override
    public synchronized void lock(long mills) throws InterruptedException, TimeOutException {

        if (mills <= 0) lock();

        long hasRemaining = mills;
        long endTime = System.currentTimeMillis() + mills;

        while (initValue) {
            if (hasRemaining <= 0) throw new TimeOutException("Time Out.");
            blockedThreadCollections.add(Thread.currentThread());
            this.wait(mills);
            hasRemaining = endTime - System.currentTimeMillis();
        }

        this.initValue = Boolean.TRUE;
        this.currentThread = Thread.currentThread();

    }

    @Override
    public synchronized void unLock() {

        if (this.currentThread == Thread.currentThread()) {
            // 解锁，代表，大家都可以竞争锁了
            this.initValue = Boolean.FALSE;
            System.out.println(Thread.currentThread().getName() + " release the lock monitor.");
            this.notifyAll();
        }

    }

    @Override
    public Collection<Thread> getBlockedThread() {
        return Collections.unmodifiableCollection(this.blockedThreadCollections);
    }

    @Override
    public int getBlockedSize() {
        return this.blockedThreadCollections.size();
    }
}
